package lee.vioson.ebook.ui.components

import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.annotation.DrawableRes
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.rememberImagePainter
import com.google.accompanist.pager.ExperimentalPagerApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import lee.vioson.composecommon.R

/**
 * 轮播图 link=https://juejin.cn/post/7006230365467574302
 * [timeMillis] 停留时间
 * [loadImage] 加载中显示的布局
 * [indicatorAlignment] 指示点的的位置,默认是轮播图下方的中间,带一点padding
 * @param indicatorVisibility 是否显示自带的指示点
 * @param imageRoundedCorner 图片圆角
 * @param extraContent 图片上面的扩展布局，一般是标题等
 * [onClick] 轮播图点击事件
 * @param onPageChanged 图片切换监听
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun <T> Banner(
    list: List<T>?,
    onImageUrl: (T) -> String,
    timeMillis: Long = 3000,
    @DrawableRes loadImage: Int = R.mipmap.pic_banner_no,
    indicatorAlignment: Alignment = Alignment.BottomCenter,
    indicatorVisibility: Boolean = true,
    imageRoundedCorner: Dp = 0.dp,
    extraContent: @Composable BoxScope.(index: Int) -> Unit = {},
    onClick: (t: T) -> Unit = {},
    onPageChanged: (page: Int) -> Unit = {}
) {

    Box(
        modifier = Modifier
            .background(MaterialTheme.colors.background)
            .fillMaxWidth()
            .height(200.dp)
    ) {

        if (list.isNullOrEmpty()) {
            //加载中的图片
            Image(
                painterResource(loadImage),
                modifier = Modifier
                    .fillMaxSize()
                    .clip(RoundedCornerShape(imageRoundedCorner)),
                contentDescription = null,
                contentScale = ContentScale.Crop
            )
        } else {
            val virtualCount = Int.MAX_VALUE
            val actualCount = list.size
            val initialPage = virtualCount / 2

            val pagerState = rememberPagerState(initialPage = initialPage)
            //监听动画执行
            var executeChangePage by remember { mutableStateOf(false) }
            var currentPageIndex = 0
            val scope = rememberCoroutineScope()
            //自动滚动
            LaunchedEffect(pagerState.currentPage, executeChangePage) {
                scope.launch {
                    delay(timeMillis)
                    with(pagerState) {
                        animateScrollToPage(currentPage + 1)
                        onPageChanged.invoke(currentPage)
                    }
                }
            }

            HorizontalPager(
                virtualCount,
                state = pagerState,
                modifier = Modifier
                    .pointerInput(pagerState.currentPage) {
                        awaitPointerEventScope {
                            while (true) {
                                //PointerEventPass.Initial - 本控件优先处理手势，处理后再交给子组件
                                val event = awaitPointerEvent(PointerEventPass.Initial)
                                //获取到第一根按下的手指
                                val dragEvent = event.changes.firstOrNull()
                                when {
                                    //当前移动手势是否已被消费
                                    dragEvent!!.isConsumed -> {
                                        return@awaitPointerEventScope
                                    }
                                    //是否已经按下(忽略按下手势已消费标记)
                                    dragEvent.changedToDownIgnoreConsumed() -> {
                                        //记录下当前的页面索引值
                                        currentPageIndex = pagerState.currentPage
                                    }
                                    //是否已经抬起(忽略按下手势已消费标记)
                                    dragEvent.changedToUpIgnoreConsumed() -> {
                                        //当页面没有任何滚动/动画的时候pagerState.targetPage为null，这个时候是单击事件
//                                        if (pagerState.targetPage == null) return@awaitPointerEventScope
                                        //当pageCount大于1，且手指抬起时如果页面没有改变，就手动触发动画
                                        if (currentPageIndex == pagerState.currentPage && list.size > 1) {
                                            executeChangePage = !executeChangePage
                                        }
                                        if (list.isNotEmpty()) {
                                            onPageChanged.invoke(
                                                (pagerState.currentPage - initialPage).floorMod(
                                                    actualCount
                                                )
                                            )
                                        }
                                    }
                                }
                            }
                        }
                    }
                    .clickable(onClick = {
                        if (list.isNotEmpty()) {
                            val actualIndex =
                                (pagerState.currentPage - initialPage).floorMod(actualCount)
                            onClick(list[actualIndex])
                        }
                    })
                    .fillMaxSize(),
            ) { page ->
                val actualIndex =
                    (page - initialPage).floorMod(actualCount)
                Box(Modifier.fillMaxSize()) {
                    Image(
                        painter = rememberImagePainter(
                            data = onImageUrl(list[actualIndex]),
                            builder = {
                                placeholder(R.mipmap.pic_banner_no)
                                error(R.mipmap.pic_banner_no)
                            }),
                        modifier = Modifier
                            .fillMaxSize()
                            .clip(RoundedCornerShape(imageRoundedCorner)),
                        contentScale = ContentScale.Crop,
                        contentDescription = null
                    )
                    extraContent.invoke(this, actualIndex)
                }
            }
            if (indicatorVisibility) {
                Box(
                    modifier = Modifier
                        .align(indicatorAlignment)
                        .padding(bottom = 6.dp, start = 6.dp, end = 6.dp)
                ) {

                    //指示点
                    Row(
                        horizontalArrangement = Arrangement.Center,
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        for (i in list.indices) {
                            val actualIndex =
                                (pagerState.currentPage - initialPage).floorMod(actualCount)
                            //大小
                            var size by remember { mutableStateOf(5.dp) }
                            size = if (actualIndex == i) 7.dp else 5.dp

                            //颜色
                            val color =
                                if (actualIndex == i) MaterialTheme.colors.primary else Color.Gray

                            Box(
                                modifier = Modifier
                                    .clip(CircleShape)
                                    .background(color)
                                    //当size改变的时候以动画的形式改变
                                    .animateContentSize()
                                    .size(size)
                            )
                            //指示点间的间隔
                            if (i != list.lastIndex) Spacer(
                                modifier = Modifier
                                    .height(0.dp)
                                    .width(4.dp)
                            )
                        }
                    }

                }
            }
        }

    }

}

fun Int.floorMod(other: Int): Int = when (other) {
    0 -> this
    else -> this - floorDiv(other = other) * other
}